home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 26
/
Cream of the Crop 26.iso
/
program
/
qlib205.zip
/
QLIB.ZIP
/
SRC
/
MATH
/
FTOA.ASM
next >
Wrap
Assembly Source File
|
1997-01-20
|
9KB
|
357 lines
;included by math_bc.asm and math_wc.asm
;data used is in math_com.asm
.code
fint macro @@QWORDPTR ;integrerize float number
fld @@QWORDPTR ;load value to get integer part
frndint ;round to integrer
fstsw ax ;store flags
fistp dptr [result] ;store (rounded) integrer
fwait
.if ah & 2 ;mask C1
mov eax,dptr [result]
dec eax
.else
mov eax,dptr [result]
.endif
endm
frnd macro @@QWORDPTR, @@DIGITS ;round "dizimas periodicas"
push eax
push ebx
push ecx
push edx ;save regs
mov edx, @@DIGITS
inc edx
callp _pow,10,edx ;pow(10, digits+1)
mov ecx, eax ;save power of 10 in ecx
fld @@QWORDPTR ;load value
fint @@QWORDPTR ;integrerize
mov dptr [tmpd], eax ;move integrer to temp buffer
fisub dptr [tmpd] ;subtract whole part
mov dptr [tmpd], ecx ;move power of 10 to temp buffer
fimul dptr [tmpd] ;mul fractional part by power
fstp qptr [result] ;store powered fractional part
fint result ;integrerize powered fractional part
xor edx, edx ;clear edx
mov ebx, 10 ;divide by 10
div ebx
xor ebx,ebx
cmp edx, 9 ;set ebx to 1 if remainder=9
sete bl
mov dptr [tmpd], ebx ;move 1 or 0 to temp buffer
fild dptr [tmpd] ;load it
mov dptr [tmpd], ecx ;move power of 10 to temp buffer
fidiv dptr [tmpd] ;divide 1 or 0 by power of 10
fstp qptr [result] ;store fractional number to add
fld @@QWORDPTR ;reload original value
fadd result ;add 0.0000xxxx1 or not
fstp @@QWORDPTR ;store rounded value
pop edx
pop ecx
pop ebx
pop eax
endm
chk_nan_inf proc private
;check for NAN and INF in st
fxam
fstsw ax
ffree st
fwait
and ah,1000111b ;mask C? flags
.if ah == 001b
callp strcpy,edi,"+NAN"
mov eax,1
ret
.endif
.if ah == 011b
callp strcpy,edi,"-NAN"
mov eax,1
ret
.endif
.if ah == 101b
callp strcpy,edi,"+INF"
mov eax,1
ret
.endif
.if ah == 111b
callp strcpy,edi,"-INF"
mov eax,1
ret
.endif
xor eax,eax
ret
chk_nan_inf endp
.data
MAX_FTOA real8 +1.0e8
MIN_FTOA real8 -1.0e8
.code
ftoa proc, a:REAL8, string:dword, decimals:dword
pushad
fld a
mov edi,string
call chk_nan_inf
.if eax
popad
mov eax,string
ret
.endif
fld a
fcomp MAX_FTOA
fstsw ax
fwait
sahf
jbe @f
jmp _etoa
@@:
fld a
fcomp MIN_FTOA
fstsw ax
fwait
sahf
jae @f
jmp _etoa
@@:
fldcw rnd_0 ;setup RC
mov [sign], 0 ;clear sign marker
fint a ;`integrerize' number
mov edi, [string] ;load EDI with string
cmp eax, 0 ;below zero?
jge @@FTOAabovezero ;NO=>goto FTOAabovezero
mov [sign], 1 ;negative number
neg eax ;clear sign bit
xor bptr[a+7],80h ;remove sign
mov [edi], bptr '-' ;put minus on start of edi
@@FTOAabovezero:
mov edx, decimals
frnd a , edx ;round .499999999 to .5
fint a ;integrerize rounded positive number
call nibblecount ;get # of digits
inc ecx ;increase (nibblecount returns #-1)
add edi, ecx ;add digit count to EDI
movzx ebx, bptr sign
add edi, ebx ;if negative one more char is needed
push ecx ;save for further use
push edi ;save for further use
mov bptr [edi], '.' ;put the point
dec edi ;decrease
mov ebx, 10 ;divider
@@FTOAloop1:
xor edx, edx ;divide eax by 10 until
div ebx ;ecx decreases from max
add edx, '0' ;number of digits to 0.
mov [edi], bptr dl ;save number MOD 10+30h
dec edi ;so it's ASCII code
dec ecx ;decrease count
jnz @@FTOAloop1
pop edi ;restore string pos at point
pop ecx ;restore digit count
inc edi ;goto after point
;*********************** [■FRACTIONAL■] ***********************
mov ecx, decimals ;make ECX a count of decimals desired
.if !ecx
mov al,'0'
stosb
jmp nodec
.endif
fint a ;`integrerize' float number
mov [tmpd], eax ;move int number to temp location
fld a ;load float number
fisub dptr [tmpd] ;subtract whole part so only frac is left
mov tmpd, 10
mov ebx, 10
@@FTOAloop2:
fimul dptr [tmpd] ;multiplicate by 10
fst qptr [result] ;save mul'ed result
fwait
fint result ;`integrerize' it
xor edx, edx ;clear edx
div ebx ;divide by 10 and get remainder
add dl, '0' ;add 30h to value
mov [edi], bptr dl ;save on string
inc edi ;increase string index
dec ecx ;decrease 'precision' counter
jnz @@FTOAloop2
nodec:
ffree st(0) ;kill st(0)
mov [edi], bptr 0 ;put '\0' at end of string
xor eax, eax
fldcw cw_def ;setup RC to default
fwait
popad
mov eax,string
ret
ftoa endp
.data
_ws db ? ;whole part sign
.code
etoa proc, a:REAL8, string:dword, decimals:dword
;print decimal part then 'e' then exponential part
pushad
fld a
mov edi,string
call chk_nan_inf
.if eax
popad
mov eax,string
ret
.endif
_etoa::
fld a
ftst ;cmp with 0.0 ;must account for decimals
fstsw ax
ffree st
fwait
sahf
.if zero?
callp ftoa,a,edi,decimals
callp strlen,edi
add edi,eax
callp strcpy,edi,"e+00"
popad
mov eax,string
ret
.endif
mov _ws,0
.if carry? ;negative #
mov _ws,1
xor bptr[a+7],80h ;remove sign bit
.endif
fldcw rnd_dw ;make sure frndint rounds towards down
callp log10,a ;get exponent part
LOADF
fstp tmpr
fwait
frnd tmpr, 1 ;round .9999999 to 1
fld tmpr
frndint ;chop decimal part
fst tmpr ;save for later
fistp tmpw ;and here trunc.
fwait
callp pow,ten,tmpr ;find 10 ** tmp
LOADF
fld a
fxch
fdivp st(1),st ;find 'a' / (10 ** tmp) which will leave the dec part
fstp tmpr ;save dec part
fwait
.if _ws ;put in neg #
mov al,'-'
stosb
.endif
callp ftoa,tmpr,edi,decimals
callp strlen,edi
add edi,eax
fldcw cw_def ;reset cw
mov al,'e'
stosb
mov bx,tmpw
.if bx & 8000h
neg bx
mov al,'-'
stosb
.else
mov al,'+'
stosb
.endif
.if bx<10 ;make sure there are at least 2 digits (as BC)
mov al,'0'
stosb
.endif
callp num2strs,bx,edi,10
popad
mov eax,string
ret
etoa endp
nibblecount proc private
push eax
push ebx
push edx
xor ecx, ecx
mov ebx, 10
@@NCloop:
xor edx, edx
div ebx
cmp eax, 0
je @@NCend
inc ecx
jmp @@NCloop
@@NCend:
pop edx
pop ebx
pop eax
ret
nibblecount endp
;This is not an ANSI C pow (this is an integer POW)
_pow PROC private uses ebx ecx edx,a1:dword,a2:dword ;power(number, power)
mov ecx, a2
cmp ecx, 0
.if carry? || zero?
mov eax,1
ret
.endif
mov ebx, a1
mov eax, ebx
xor edx, edx
jmp start
@@:
mul ebx
start:
dec ecx
jnz @b
ret
_pow ENDP